package com.clj.blesample;

import android.Manifest;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.AdvertiseCallback;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.arashivision.nativeutils.Log;
import com.arashivision.onecamera.OneDriverInfo;
import com.arashivision.onecamera.Options;
import com.arashivision.onecamera.PhotoOptions;
import com.arashivision.onecamera.camerarequest.CalibrateGyro;
import com.arashivision.onecamera.camerarequest.GetMiniThumbnail;
import com.arashivision.onecamera.camerarequest.GetTimelapseOptions;
import com.arashivision.onecamera.camerarequest.SetTimelapseOptions;
import com.arashivision.onecamera.camerarequest.StartTimelapse;
import com.arashivision.onecamera.camerarequest.StopTimelapse;
import com.arashivision.onecamera.camerarequest.TakePicture;
import com.arashivision.onecamera.camerarequest.TestSDCardSpeed;
import com.arashivision.onecamera.camerarequest.TimelapseOptionsInfo;
import com.arashivision.onecamera.cameraresponse.GetOptionsResp;
import com.arashivision.onecamerademo.R;
import com.clj.fastble.data.ScanResult;
import com.clj.fastble.utils.BleLog;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.util.ArrayList;
import java.util.List;

public class AnyScanActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "AnyScanActivity";
    private Button btn_start, btn_stop,btn_start_bc,btn_stop_bc;
    private boolean bScanConnect,mBroadCast;
    private String scanConnectName = "Insta360 One4567879";
    private String mac = "00";
    private TextView tv_cost;
    private ImageView img_loading;
    private Animation operatingAnim;
    private ResultAdapter mResultAdapter;
    private ListView listView_device;
    private OperationAdapter mOpAdapter;
    private ProgressDialog progressDialog;
    private enum ConnectState { Idle, Connecting, ConnectComplete, Error }
    private enum RecordState { Idle, Recording,Stopping, Error }
    private RecordState mRecordState = RecordState.Idle;
    private ConnectState mConnectState = ConnectState.Idle;

//    private BluetoothService mBluetoothService;
    private BleService mBluetoothService;
    private String lastPicUrl= "/DCIM/Camera01/IMG_20170104_102819_041.insp";
    private String mOPArray [] = {
            "SyncCaptureStatus",
            "GetMiniTumbnail",
            "TakePictureHDR",
            "StartCapture",
            "StopCapture",
            "StartTimelapse",
            "StopTimelapse",
            "CaptureStatus",
            "PhotoOptions",
            "CalibrateGyro",
            "getAllOption",
            "TakePicture",
            "eraseSdcard",
            "readRssi",
            "switchAndroid",
            "switchIOS",
            "getOS",
            "getAllOptionsAsync",
            "getAllPhotoOptionsAsync",
            "setOptionsAsync",
            "setPhotoOptionsAsync",
            "startIntervalShotting",
            "setTimelapseAsync",
            "getTimelapseAsync",
            "reboot",
            "setTimelapseAsyncTO",
    };

    private Object syncCmd = new Object();

    private Object mResult = new Object();
    private int mCmdWhat;
    private int mCmdError;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_any_scan);
        EventBus.getDefault().register(this);
        initView();
        mBluetoothService = BleService.instance(this.getApplicationContext());

        mBluetoothService.setInfoNotify(new BleService.InfoNotify()
        {
            @Override
            public void infoNotify(int what,int error,Object obj)
            {
                if(error != 0)
                {
                    synchronized (syncCmd)
                    {
                        mCmdWhat = what;
                        mResult = obj;
                        mCmdError= error;
                        syncCmd.notifyAll();
                    }
                }
            }
        });
    }

    @Override
    protected void onStart()
    {
        super.onStart();
        BleLog.i("onStart");
    }

    @Override
    protected void onDestroy() {
        BleLog.i("onDestroy mConnectState " + mConnectState);
        mBluetoothService.closeConnect();

        mBluetoothService = null;
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_start:
                bScanConnect = true;
                mBroadCast = false;
                setScanAdpater();
                checkPermissions();
                break;
            case R.id.btn_bc:
                bScanConnect = false;
                mBroadCast = true;
                checkPermissions();
                break;
            case R.id.btn_stop_bc:
                stopBroadcast();
                break;
            case R.id.btn_stop:
                if (mBluetoothService != null) {
                    mBluetoothService.cancelScan();
                }
                break;
        }
    }

    private void setScanAdpater()
    {
        listView_device.setAdapter(mResultAdapter);
        listView_device.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (mBluetoothService != null) {
                    mBluetoothService.cancelScan();
                    scanConnectName = mResultAdapter.getItem(position).getDevice().getName();
                    mac = mResultAdapter.getItem(position).getDevice().getAddress();
                    mBluetoothService.connectDevice(mResultAdapter.getItem(position),false);
                    mConnectState = ConnectState.Connecting;
                    mResultAdapter.clear();
                    mResultAdapter.notifyDataSetChanged();
                }
            }
        });

        listView_device.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                if (mBluetoothService != null) {
                    mBluetoothService.cancelScan();
                    scanConnectName = mResultAdapter.getItem(position).getDevice().getName();
                    mac = mResultAdapter.getItem(position).getDevice().getAddress();
                    mBluetoothService.connectDevice(mResultAdapter.getItem(position),true);
                    mConnectState = ConnectState.Connecting;
                    mResultAdapter.clear();
                    mResultAdapter.notifyDataSetChanged();
                    return true;
                }
                return false;
            }
        });
    }

    private void initView() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        toolbar.setTitle("搜索设备");
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });

        btn_start = (Button) findViewById(R.id.btn_start);
        btn_start.setOnClickListener(this);

        btn_start_bc = (Button) findViewById(R.id.btn_bc);
        btn_start_bc.setOnClickListener(this);

        btn_stop_bc = (Button) findViewById(R.id.btn_stop_bc);
        btn_stop_bc.setOnClickListener(this);

        btn_stop = (Button) findViewById(R.id.btn_stop);
        btn_stop.setOnClickListener(this);

        tv_cost = (TextView) findViewById(R.id.tv_cost);
        tv_cost.setOnClickListener(this);
        tv_cost.setEnabled(true);

        img_loading = (ImageView) findViewById(R.id.img_loading);
        operatingAnim = AnimationUtils.loadAnimation(this, R.anim.rotate);
        operatingAnim.setInterpolator(new LinearInterpolator());
        progressDialog = new ProgressDialog(this);

        mResultAdapter = new ResultAdapter(this);
        listView_device = (ListView) findViewById(R.id.list_device);
    }

    private void testSDCardSpeed()
    {
        TestSDCardSpeed obj = new TestSDCardSpeed();
        obj.block_size = 4096;
        obj.duration = 60;
        obj.times = 3;

        mBluetoothService.testSDCardSpeed(obj);
    }

    private void eraseSdcard()
    {
        long eraseId = mBluetoothService.eraseSDCard();
        Log.d(TAG,"erase id " + eraseId);
    }

    private void readRssi()
    {
        boolean bRet = mBluetoothService.readRssi();
        BleLog.i("read rss i bRet " + bRet);
    }

    private void switchAndroid()
    {
        Options mOptions = new Options();
        mOptions.setAdoptionSystem(OneDriverInfo.Options.AdoptionSystem.PHONE_ANDROID);
        long bRet = mBluetoothService.setOptionsAsync(mOptions);
        BleLog.i("switchAndroid bRet " + bRet);
    }

    private void switchIOS()
    {
        Options mOptions = new Options();
        mOptions.setAdoptionSystem(OneDriverInfo.Options.AdoptionSystem.PHONE_IOS);
        long bRet = mBluetoothService.setOptionsAsync(mOptions);
        BleLog.i("switchIOS bRet " + bRet);
    }

    private Options startWait(long id,int cmd)
    {
        synchronized (syncCmd)
        {
            try
            {
                mCmdWhat = -1;
                mCmdError = -1;
                mResult = null;
                syncCmd.wait(10000);
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        Options result = null;
        if(mResult != null && mCmdWhat != -1)
        {
            if(mCmdWhat == cmd)
            {
                GetOptionsResp resp = (GetOptionsResp)mResult;
                if(id == resp.requestID)
                {
                    result = resp.result;
                }
                else
                {
                    android.util.Log.e(TAG,"error testGetOptions mismatch (" +
                            id + "," + resp.requestID +") cmd " + cmd);
                }

            }
        }

        return result;
    }

    private Options testGetOptions(List<String> list)
    {
        return  startWait(mBluetoothService.getOptionsAsync(list),OneDriverInfo.Response.InfoType.GET_OPTIONS);
    }

    private void getOS()
    {
        List<String> mOptionList = new ArrayList<>();
        mOptionList.add(OneDriverInfo.Options.APOPTION_SYSTEM);

        Options mOptions = testGetOptions(mOptionList);
        if(mOptions != null)
        {
            if(mOptions.getAdoptionSystem() ==  OneDriverInfo.Options.AdoptionSystem.PHONE_IOS)
            {
                BleLog.i("ios");
            }
            else
            {
                BleLog.i("android");
            }
        }
        else
        {
            BleLog.e("error");
        }
    }

    private void getAllOptionsAsync()
    {
        long id = mBluetoothService.getAllOptionsAsync();
        BleLog.i("getAllOptionsAsync " + id);
    }

    private void getAllPhotoOptionsAsync()
    {
        long id = mBluetoothService.getPhotoOptionsAsync(OneDriverInfo.PhotoOptionsConstants.FunctionMode.FUNCMODE_NORMAL);
        BleLog.i("getAllPhotoOptionsAsync " + id);
    }

    private void setOptionsAsync()
    {
        Options mOptions = new Options();
        mOptions.setAdoptionSystem(OneDriverInfo.Options.AdoptionSystem.PHONE_ANDROID);
        long id = mBluetoothService.setOptionsAsync(mOptions);
        BleLog.i("setOptionsAsync " + id);
    }

    private void setPhotoOptionsAsync()
    {
        PhotoOptions mOptions = new PhotoOptions();
        mOptions.setSharpness(6);
        long id = mBluetoothService.setPhotoOptionsAsync(OneDriverInfo.PhotoOptionsConstants.FunctionMode.FUNCMODE_NORMAL,mOptions);
        BleLog.i("setPhotoOptionsAsync " + id);
    }

    private void testCaptureStillImage(int mode)
    {
        Log.i(TAG, "testCaptureStillImage mode " + mode);
        TakePicture obj = new TakePicture();
        obj.extra_metadata = null;

        obj.mode = OneDriverInfo.Request.ImageMode.NORMAL;
        switch(mode)
        {
            case OneDriverInfo.Request.ImageMode.NORMAL:
                break;
            case OneDriverInfo.Request.ImageMode.AEB:
                obj.aeb_ev_bias = new int[3];
                obj.aeb_ev_bias[0] = 0;
                obj.aeb_ev_bias[1] = 1;
                obj.aeb_ev_bias[2] = 2;
                break;
            default:
                break;
        }

        mBluetoothService.captureStillImage(obj,0);
    }

    private void startCaptureWithStorage()
    {
        int ret = mBluetoothService.startRecord();

        mRecordState = RecordState.Recording;
        Log.d(TAG,"startCaptureWithStorage ret " + ret);
    }

    private void calibrateGyro()
    {
        CalibrateGyro obj = new CalibrateGyro();
        obj.gyro_count = 100;
        mBluetoothService.calibrateGyro(obj);
    }

    private void getMiniThumbnail()
    {
        GetMiniThumbnail obj = new GetMiniThumbnail();

        obj.uri = lastPicUrl;
        mBluetoothService.getMiniThumbnail(obj);
    }

    private void stopRecord() {
        Log.i(TAG, "stop recording...");
        String extraData = "";
        mBluetoothService.stopRecord(extraData.getBytes());
        mRecordState = RecordState.Stopping;
    }

    private void resetRecord() {
        Log.i(TAG, "reset record");
        mBluetoothService.resetRecord();
        mRecordState = RecordState.Idle;
    }

    private void startTimelapse(int mode)
    {
        StartTimelapse obj = new StartTimelapse();
        obj.mode = mode;
        mBluetoothService.startTimeplapse(obj,30 *1000);
    }

    private void setTimelapseAsync(int mode)
    {
        SetTimelapseOptions obj = new SetTimelapseOptions();
        obj.mode = mode;
        obj.timelapse_options = new TimelapseOptionsInfo();
        obj.timelapse_options.durationS = 5;
        obj.timelapse_options.lapseTimeMs = 2000;
        long ret = mBluetoothService.setTimelapseOptionsAsync(obj);
        BleLog.i("setTimelapseOptionsAsync ret " + ret);
    }

    private void setTimelapseAsyncTO(int mode)
    {
        SetTimelapseOptions obj = new SetTimelapseOptions();
        obj.mode = mode;
        obj.timelapse_options = new TimelapseOptionsInfo();
        obj.timelapse_options.durationS = 30;
        obj.timelapse_options.lapseTimeMs = 20000;
        long ret = mBluetoothService.setTimelapseOptionsAsync(obj);
        BleLog.i("setTimelapseOptionsAsync ret " + ret);
    }

    private void reboot()
    {
        mBluetoothService.reboot();
        BleLog.i("reboot " );
    }

    private void getTimelapseAsync(int mode)
    {
        GetTimelapseOptions obj = new GetTimelapseOptions();
        obj.mode = mode;
        long ret=  mBluetoothService.getTimelapseOptionsAsync(obj);
        BleLog.i("getTimelapseAsync ret " + ret);
    }

    private void stopTimelapse()
    {
        StopTimelapse obj = new StopTimelapse();
        mBluetoothService.stopTimeplapse(obj);
    }

    private void getCaptureStatus()
    {
        mBluetoothService.getRecordStatus();
    }

    private void syncCaptureStatus()
    {
        mBluetoothService.syncCaptureStatus();
    }

    private void getPhotoOptions()
    {
        int mode = OneDriverInfo.PhotoOptionsConstants.FunctionMode.FUNCMODE_NORMAL;

        mBluetoothService.getPhotoOptionsAsync(mode);
    }

    private void getAllOptions()
    {
        mBluetoothService.getAllOptionsAsync();
    }

    private void initOpAdapter()
    {
        BleLog.i(TAG,"initOpAdapter");
        mOpAdapter = new OperationAdapter(this);
        ListView listView_device = (ListView) findViewById(R.id.list_device);
        listView_device.setAdapter(mOpAdapter);
        listView_device.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (mBluetoothService != null) {
                    BleLog.i("OpAdapter position " + position );
                    long start = System.nanoTime();
                    switch(position)
                    {
                        case 0:
                            syncCaptureStatus();
                            break;
                        case 1:
                            getMiniThumbnail();
                            break;
                        case 2:
                            testCaptureStillImage(OneDriverInfo.Request.ImageMode.AEB);
                            break;
                        case 3:
                            startCaptureWithStorage();
                            break;
                        case 4:
                            stopRecord();
                            break;
                        case 5:
                            startTimelapse(OneDriverInfo.Request.TimelapseMode.TIMELAPSE_VIDEO);
                            break;
                        case 6:
                            stopTimelapse();
                            break;
                        case 7:
                            getCaptureStatus();
                            break;
                        case 8:
                            getPhotoOptions();
                            break;
                        case 9:
                            calibrateGyro();
                            break;
                        case 10:
                            getAllOptions();
                            break;
                        case 11:
                            testCaptureStillImage(OneDriverInfo.Request.ImageMode.NORMAL);
                            break;
                        case 12:
                            eraseSdcard();
                            break;
                        case 13:
                            readRssi();
                            break;
                        case 14:
                            switchAndroid();
                            break;
                        case 15:
                            switchIOS();
                            break;
                        case 16:
                            getOS();
                            break;
                        case 17:
                            getAllOptionsAsync();
                            break;
                        case 18:
                            getAllPhotoOptionsAsync();
                            break;
                        case 19:
                            setOptionsAsync();
                            break;
                        case 20:
                            setPhotoOptionsAsync();
                            break;
                        case 21:
                            startTimelapse(OneDriverInfo.Request.TimelapseMode.TIMELAPSE_INTERVAL_SHOOTING);
                            break;
                        case 22:
                            setTimelapseAsync(OneDriverInfo.Request.TimelapseMode.TIMELAPSE_VIDEO);
                            break;
                        case 23:
                            getTimelapseAsync(OneDriverInfo.Request.TimelapseMode.TIMELAPSE_VIDEO);
                            break;
                        case 24:
                            reboot();
                            break;
                        case 25:
                            setTimelapseAsyncTO(OneDriverInfo.Request.TimelapseMode.TIMELAPSE_VIDEO);
                            break;
                    }
                    long end = System.nanoTime();
                    Log.i(TAG," cost " + (end - start));
                    String cost = (end - start)/1000000 + "";
                    tv_cost.setText(cost);
                }
            }
        });

        for(String str: mOPArray)
        {
            mOpAdapter.addResult(str);
        }

        mOpAdapter.notifyDataSetChanged();
        BleLog.i(TAG,"initOpAdapter suc");
    }

    private class OperationAdapter extends BaseAdapter {

        private Context context;
        private List<String> scanResultList;

        OperationAdapter(Context context) {
            this.context = context;
            scanResultList = new ArrayList<>();
        }

        void addResult(String result) {
            scanResultList.add(result);
        }

        void clear() {
            scanResultList.clear();
        }

        @Override
        public int getCount() {
            return scanResultList.size();
        }

        @Override
        public String getItem(int position) {
            if (position > scanResultList.size())
                return null;
            return scanResultList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            OperationAdapter.ViewHolder holder;
            if (convertView != null) {
                holder = (OperationAdapter.ViewHolder) convertView.getTag();
            } else {
                convertView = View.inflate(context, R.layout.adapter_operation, null);
                holder = new OperationAdapter.ViewHolder();
                convertView.setTag(holder);
                holder.txt_name = (TextView) convertView.findViewById(R.id.txt_name);
            }

            String result = scanResultList.get(position);
            holder.txt_name.setText(result);
            return convertView;
        }

        class ViewHolder {
            TextView txt_name;
        }
    }

    private class ResultAdapter extends BaseAdapter {

        private Context context;
        private List<ScanResult> scanResultList;

        ResultAdapter(Context context) {
            this.context = context;
            scanResultList = new ArrayList<>();
        }

        void addResult(ScanResult result) {
            scanResultList.add(result);
        }

        void clear() {
            scanResultList.clear();
        }

        @Override
        public int getCount() {
            return scanResultList.size();
        }

        @Override
        public ScanResult getItem(int position) {
            if (position > scanResultList.size())
                return null;
            return scanResultList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ResultAdapter.ViewHolder holder;
            if (convertView != null) {
                holder = (ResultAdapter.ViewHolder) convertView.getTag();
            } else {
                convertView = View.inflate(context, R.layout.adapter_scan_result, null);
                holder = new ResultAdapter.ViewHolder();
                convertView.setTag(holder);
                holder.txt_name = (TextView) convertView.findViewById(R.id.txt_name);
                holder.txt_mac = (TextView) convertView.findViewById(R.id.txt_mac);
                holder.txt_rssi = (TextView) convertView.findViewById(R.id.txt_rssi);
            }

            ScanResult result = scanResultList.get(position);
            BluetoothDevice device = result.getDevice();
            String name = device.getName();
            String mac = device.getAddress();
            int rssi = result.getRssi();
            holder.txt_name.setText(name);
            holder.txt_mac.setText(mac);
            holder.txt_rssi.setText(String.valueOf(rssi));
            return convertView;
        }

        class ViewHolder {
            TextView txt_name;
            TextView txt_mac;
            TextView txt_rssi;
        }
    }

//    private void bindService() {
//        Intent bindIntent = new Intent(this, BluetoothService.class);
//        this.bindService(bindIntent, mFhrSCon, Context.BIND_AUTO_CREATE);
//    }
//
//    private void unbindService() {
//        this.unbindService(mFhrSCon);
//    }
//
//    private ServiceConnection mFhrSCon = new ServiceConnection() {
//        @Override
//        public void onServiceConnected(ComponentName name, IBinder service) {
//            mBluetoothService = ((BluetoothService.BluetoothBinder) service).getService();
//            mBluetoothService.setScanCallback(callback);
//            BleLog.i("start scan");
//            mBluetoothService.scanDevice();
//        }
//
//        @Override
//        public void onServiceDisconnected(ComponentName name) {
//            mBluetoothService = null;
//        }
//    };

    private void startScan() {
        BleLog.i("bScanConnect " +
                bScanConnect);
//        mBluetoothService.closeConnect();
        if(bScanConnect)
        {
            mBluetoothService.scanDevice();
        }
        else
        {
            int to = 0;
            byte power = -59;
            mBluetoothService.startBroadCast(to,power);
        }
    }

    private void stopBroadcast()
    {
        mBluetoothService.stopBroadCast();
    }


    @Override
    public final void onRequestPermissionsResult(int requestCode,
                                                 @NonNull String[] permissions,
                                                 @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case 12:
                if (grantResults.length > 0) {
                    for (int i = 0; i < grantResults.length; i++) {
                        if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                            onPermissionGranted(permissions[i]);
                        }
                    }
                }
                break;
        }
    }

    private void checkPermissions() {
        String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION};
        List<String> permissionDeniedList = new ArrayList<>();
        for (String permission : permissions) {
            int permissionCheck = ContextCompat.checkSelfPermission(this, permission);
            if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
                onPermissionGranted(permission);
            } else {
                permissionDeniedList.add(permission);
            }
        }
        if (!permissionDeniedList.isEmpty()) {
            String[] deniedPermissions = permissionDeniedList.toArray(new String[permissionDeniedList.size()]);
            ActivityCompat.requestPermissions(this, deniedPermissions, 12);
        }
    }

    private void onPermissionGranted(String permission) {
        switch (permission) {
            case Manifest.permission.ACCESS_FINE_LOCATION:
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !checkGPSIsOpen()) {
                    new AlertDialog.Builder(this)
                            .setTitle(R.string.notifyTitle)
                            .setMessage(R.string.gpsNotifyMsg)
                            .setNegativeButton(R.string.cancel,
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            finish();
                                        }
                                    })
                            .setPositiveButton(R.string.setting,
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                                            startActivityForResult(intent, 1);
                                        }
                                    })

                            .setCancelable(false)
                            .show();
                } else {
                    startScan();
                }
                break;
        }
    }

    private boolean checkGPSIsOpen() {
        LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        if (locationManager == null)
            return false;
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1) {
            if (checkGPSIsOpen()) {
                startScan();
            }
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onRecordCompleteWithStorageEvent(BleService.RecordCompleteWithStorageEvent event)
    {
        BleLog.i("onRecordCompleteWithStorageEvent error_code　" + event.mResult.error_code);
        BleLog.i("onRecordCompleteWithStorageEvent total_time　" + event.mResult.video.total_time);
        BleLog.i("onRecordCompleteWithStorageEvent file_size　" + event.mResult.video.file_size);
        BleLog.i("onRecordCompleteWithStorageEvent uri　" + event.mResult.video.uri);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onTakePictureWithStorageEvent(BleService.TakePictureWithStorageEvent event)
    {
        BleLog.i("onTakePictureWithStorageEvent state　" + event.mResult.error_code);
        BleLog.i("onTakePictureWithStorageEvent uri　" + event.mResult.image.uri);
        BleLog.i("onTakePictureWithStorageEvent file_size　" + event.mResult.image.file_size);
        BleLog.i("onTakePictureWithStorageEvent s_thumbnail　" + event.mResult.image.s_thumbnail.length);
        lastPicUrl = event.mResult.image.uri;
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onTimelapseNotifyEvent(BleService.TimelapseNotifyEvent event)
    {
        BleLog.i("onTimelapseNotifyEvent state　" + event.state);
        BleLog.i("onTimelapseNotifyEvent error_code　" + event.mResult.error_code);
        BleLog.i("onTimelapseNotifyEvent total_time　" + event.mResult.video.total_time);
        BleLog.i("onTimelapseNotifyEvent file_size　" + event.mResult.video.file_size);
        BleLog.i("onTimelapseNotifyEvent uri　" + event.mResult.video.uri);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onServicesDiscoveredEvent(BleService.ServicesDiscoveredEvent event)
    {
        BleLog.i("onServicesDiscovered ");
        mConnectState = ConnectState.ConnectComplete;
        if(event.mCaptureStatus.state != OneDriverInfo.Response.CameraCaptureState.NOT_CAPTURE)
        {
            mRecordState = RecordState.Recording;
        }
//        img_loading.clearAnimation();
        progressDialog.dismiss();
        new Handler(Looper.getMainLooper()).postAtTime(new Runnable()
         {
             @Override
             public void run()
             {
                 initOpAdapter();
             }
         }
        ,500);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onServicesDiscoveredFailEvent(BleService.ServicesDiscoveredFailEvent event)
    {
        BleLog.i("onServicesDiscovered Fail ");
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onStartScanEvent(BleService.StartScanEvent event) {
        BleLog.i("onStartScan");
        mResultAdapter.clear();
        mResultAdapter.notifyDataSetChanged();
        img_loading.startAnimation(operatingAnim);
        btn_start.setEnabled(false);
        btn_start_bc.setEnabled(false);
        btn_stop_bc.setEnabled(false);
        btn_stop.setVisibility(View.VISIBLE);
    }

    public static String bytesToHexString(byte[] src){
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onScanningEvent(BleService.ScanningEvent event) {
//        BleLog.i("onScanningEvent " + event.result.toString());
//        if(event.result.getDevice().getName() != null &&
//                (event.result.getDevice().getName().contains("Insta360 ONE") || event.result.getDevice().getName().contains("Cath Kiston")))
        {
            if(event.result.getDevice().getName() != null)
            {
                BleLog.i("event.result.getDevice().getName()  "
                        + event.result.getDevice().getName() +
                        " len " + event.result.getDevice().getName().length());
            }


            byte[] scanData = event.result.getScanRecord();

            BleLog.i("2scan record " + scanData.length);
            if(event.result.getDevice().getUuids() != null)
            {
                BleLog.i("scan record uuid len " +
                        event.result.getDevice().getUuids().length);

                for(ParcelUuid uuid:event.result.getDevice().getUuids())
                {
                    BleLog.i("uuid " + uuid.toString());
                }
            }


            BleLog.i("scan record str " + bytesToHexString(scanData));

            mResultAdapter.addResult(event.result);
            mResultAdapter.notifyDataSetChanged();
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onScanCompleteEvent(BleService.ScanCompleteEvent event) {
        BleLog.i("onScanComplete");
        img_loading.clearAnimation();
        btn_start.setEnabled(true);

        btn_start_bc.setEnabled(true);
        btn_stop_bc.setEnabled(true);
        btn_stop.setVisibility(View.INVISIBLE);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onConnectingEvent(BleService.ConnectingEvent event) {
        BleLog.i("onConnecting");
        progressDialog.show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onConnectFailEvent(BleService.ConnectFailEvent event) {
        BleLog.i("onConnectFail");
        img_loading.clearAnimation();
        btn_start.setEnabled(true);
        btn_start_bc.setEnabled(true);
        btn_stop_bc.setEnabled(true);
        btn_stop.setVisibility(View.INVISIBLE);
        progressDialog.dismiss();
        Toast.makeText(AnyScanActivity.this, "连接失败", Toast.LENGTH_LONG).show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onDisConnectedEvent(BleService.DisConnectedEvent event) {
        BleLog.i("onDisConnectedEvent");
        progressDialog.dismiss();
        mResultAdapter.clear();
        mResultAdapter.notifyDataSetChanged();
        img_loading.clearAnimation();
        btn_start.setEnabled(true);
        btn_start_bc.setEnabled(true);
        btn_stop_bc.setEnabled(true);
        btn_stop.setVisibility(View.INVISIBLE);
        Toast.makeText(AnyScanActivity.this, "连接断开", Toast.LENGTH_LONG).show();
        mBluetoothService.closeConnect();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onBleErrorEvent(BleService.BleErrorEvent event) {
        BleLog.i("onBleErrorEvent　" + event.error);
        mBluetoothService.closeConnect();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onScanFailEvent(BleService.ScanFailEvent event) {
        BleLog.i("ScanFailEvent");
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onReadRssiEvent(BleService.ReadRssiEvent event) {
        BleLog.i("onReadRssiEvent　"+ event.rssi);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onStartBCSuccessEvent(BleService.StartBCSuccessEvent event) {
        BleLog.i("onStartBCSuccessEvent　");
        Toast.makeText(AnyScanActivity.this, "发送广播成功", Toast.LENGTH_LONG).show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onStartBCFailEvent(BleService.StartBCFailEvent event) {
        int errorCode = event.errorCode;
        BleLog.i("onStartBCFailEvent　" + errorCode);
        if (errorCode == AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE) {
            Toast.makeText(AnyScanActivity.this, "advertise_failed_data_too_large", Toast.LENGTH_LONG).show();
            BleLog.e("Failed to start advertising as the advertise data to be broadcasted is larger than 31 bytes.");
        } else if (errorCode == AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS) {
            Toast.makeText(AnyScanActivity.this, "advertise_failed_too_many_advertises", Toast.LENGTH_LONG).show();
           BleLog.e( "Failed to start advertising because no advertising instance is available.");

        } else if (errorCode == AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED) {
            Toast.makeText(AnyScanActivity.this, "advertise_failed_already_started", Toast.LENGTH_LONG).show();
           BleLog.e( "Failed to start advertising as the advertising is already started");

        } else if (errorCode == AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR) {
            Toast.makeText(AnyScanActivity.this, "advertise_failed_internal_error", Toast.LENGTH_LONG).show();
           BleLog.e( "Operation failed due to an internal error");

        } else if (errorCode == AdvertiseCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED) {
            Toast.makeText(AnyScanActivity.this, "advertise_failed_feature_unsupported", Toast.LENGTH_LONG).show();
           BleLog.e( "This feature is not supported on this platform");
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onStopBCSuccessEvent(BleService.StopBCSuccessEvent event) {
        BleLog.i("onStopBCSuccessEvent　");
        Toast.makeText(AnyScanActivity.this, "停止广播成功", Toast.LENGTH_LONG).show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onStopBCFailEvent(BleService.StopBCFailEvent event) {
        int errorCode = event.errorCode;
        BleLog.i("StopBCFailEvent　" + errorCode);
        Toast.makeText(AnyScanActivity.this, "停止广播失败 " + errorCode, Toast.LENGTH_LONG).show();
    }
}
